﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.UI;
using Warensoft.DataService.DBHelpers;
using Warensoft.Unity.Communication.Client;
using Warensoft.Unity.Communication.Client.DataClient;
using Warensoft.Unity.Communication.Client.Models;

namespace Warensoft.DataService
{
    public class DataService
    {
        DBHelper dbHelper;
        private string connectionStringName = "";
        private DataSet typedDataSet;
        private Dictionary<string, DataServiceDataAdapter> dataAdapters = new Dictionary<string, DataServiceDataAdapter>();
        protected DataService(string connectionStringName,DataSet typedDataSet)
        {
            this.typedDataSet = typedDataSet;
            this.connectionStringName = connectionStringName;
            this.dbHelper= DBHelper.Create(DatabaseType.MSSqlServer,this.typedDataSet);
        }
        static Page currentHostPage;
        static DataService service;
        private string ConnectionString
        {
            get
            {
                return ConfigurationManager.ConnectionStrings[this.connectionStringName].ConnectionString;
            }
        }
        public static void Create(Page hostPage, string connectionStringName, DataSet typedDataSet)
        {
            currentHostPage = hostPage;
            if (service == null)
            {
                service = new DataService(connectionStringName, typedDataSet);
            }

            if (hostPage.Request.ContentLength != 0 && hostPage.Request.HttpMethod == "POST")
            {
                var strm = hostPage.Request.InputStream;
                var buffer = new byte[hostPage.Request.ContentLength];
                strm.Read(buffer, 0, buffer.Length);
                DataServicePackage package = DataServicePackage.Create(buffer);
                DataServicePackage result = service.ProcessMessage(package);
                hostPage.Response.BinaryWrite(result.ToArray());
                hostPage.Response.End();
            }
        }

        public DataServicePackage ProcessMessage(DataServicePackage package)
        {
            //throw new Exception("hello world");
            DataServicePackage result = new DataServicePackage();
            result.Command = package.Command;
            result.ID = package.ID;
            switch (package.Command)
            {
                case "GetData":
                    string tableName = package.CommandText;
                    DataQuery query = DataQuery.Create ((package.Result.AdditionalData as byte[]));
                    result.Result = new ResultInfo();
                    try
                    {
                       result.Result .AdditionalData = this.dataAdapters[tableName].GetData(query);
                       result.Result.OperationDone = true;
                    }
                    catch (Exception ex)
                    {
                        result.Result.Message = ex.Message;
                    }
                    break;
                case "BatchUpdate":
                    List<DataEntity> entities = (package.Result.AdditionalData as byte[]).ToDataEntityList();
                    var groupedEntities = entities.GroupBy(entity=>entity.TableName );
                    ResultInfo resultInfo = new ResultInfo();
                    resultInfo.OperationDone = true;
                    try
                    {
                        foreach (var group in groupedEntities)
                        {
                            var updateEntities = group.Where(entity => entity.State == EntityState.Changed).ToList();
                            var deletedEntities = group.Where(entity => entity.State == EntityState.Deleted).ToList();
                            var insertedEntities = group.Where(entity => entity.State == EntityState.Added).ToList();
                            var adpt = this.dataAdapters[group.First().TableName];
                            adpt.Update(updateEntities,package.RefreshMode);
                            adpt.Delete(deletedEntities, package.RefreshMode);
                            adpt.Insert(insertedEntities);
                        }
                    }
                    catch (Exception ex)
                    {

                        resultInfo.OperationDone = false;
                        resultInfo.Message = ex.Message;
                    }

                    result.Result = resultInfo;
                    break;
                //case "ExecuteNonQuery":
                //    result.Result = service.dbHelper.ExecuteNonQuery(this.ConnectionString, package.CommandText, package.Parameters);

                //    break;
                //case "CreateDataSet":
                //    result.Result = service.dbHelper.CreateDataSet(this.ConnectionString, package.CommandText, package.Parameters);

                //    break;
                case "GetSchema":

                    DataSet ds = new DataSet();
                    
                    StringBuilder sbSchema=new StringBuilder ();
                    StringWriter sw=new StringWriter (sbSchema);
                    this.typedDataSet .WriteXml (sw, XmlWriteMode.WriteSchema);
                    result.Result = new ResultInfo()
                    {
                        OperationDone = true,
                        AdditionalData = sbSchema.ToString ()
                    };
                    foreach (DataTable table in this.typedDataSet .Tables)
                    {
                        if (this.dataAdapters .ContainsKey(table .TableName )==false )
                        {
                            this.dataAdapters.Add(table.TableName, new DataServiceDataAdapter(table, this.dbHelper, this.ConnectionString));

                        }
                    }
                    break;
                default:
                    break;
            }
            return result;
        }
    }
}
